package com.computer.network.security.filter;

import com.computer.network.security.CustomerUserDetailsService;
import com.computer.network.security.ex.CustomSecurityException;
import com.computer.network.security.handler.LoginFailureHandler;
import com.computer.network.service.AuthorityService;
import com.computer.network.service.RedisService;
import com.computer.network.util.JwtUtil;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 过滤器
 * 不明白上下文为什么为空，待解决
 * 判断redis存在后，后续锁续命可能不存在，锁续命内部也存在原子性问题，待解决
 */
@Data
@Component
public class CheckTokenFilter extends OncePerRequestFilter {
    @Resource
    JwtUtil jwtUtil;
    @Resource
    RedisService redisService;
    @Resource
    CustomerUserDetailsService customerUserDetailsService;
    @Resource
    LoginFailureHandler loginFailureHandler;
    @Value("${values.loginUrl}")
    private String loginUrl;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException, AuthenticationException {
        try {
            UserDetails userDetails = null;
            //创建请求信息
            WebAuthenticationDetails webAuthenticationDetails = new WebAuthenticationDetailsSource().buildDetails(httpServletRequest);
            //@value获取的值比较错误，待解决
//            StringBuffer requestURI = new StringBuffer(httpServletRequest.getRequestURI());
//            StringBuffer url = new StringBuffer(loginUrl);
//            System.out.println(httpServletRequest.getRequestURI());
//            System.out.println(loginUrl);
            //判断是否需要验证，登录请求直接放过
            if (httpServletRequest.getRequestURI().equals("/api/user/login")) {
                doFilter(httpServletRequest, httpServletResponse, filterChain);
            }
            String tokenHeader = null;
            //判断请求头
            if (httpServletRequest.getHeader("token") != null) {
                tokenHeader = httpServletRequest.getHeader("token");
            }
            //判断请求体
            else if (httpServletRequest.getParameter("token") != null) {
                tokenHeader = httpServletRequest.getParameter("token");
            }
            //判断有无token
            if (tokenHeader != null) {
                //获取用户名
                final String usernameFromToken = jwtUtil.getUsernameFromToken(tokenHeader);
                if (usernameFromToken == null) {
                    throw new CustomSecurityException("用户信息验证失败");
                }
                //上下文拿不到用户信息，待解决
//                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//                System.out.println("用户信息" + authentication);
                //数据库获取用户信息
                // userDetails = customerUserDetailsService.loadUserByUsername(usernameFromToken);
                //redis获取用户信息，redis-V的用户信息是在用户登录查询数据库得到的
                userDetails = redisService.LoginSelectRedis(tokenHeader);
                //判断token是否有效,无效用户信息无效
                if (jwtUtil.validateToken(tokenHeader, userDetails)) {
                    //判断redis里面是否有token,无则返回用户信息已过期
                    if (redisService.LoginIsRedis(tokenHeader) == true) {
                        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
                                = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                        //设置请求信息
                        usernamePasswordAuthenticationToken.setDetails(webAuthenticationDetails);
                        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
                        doFilter(httpServletRequest, httpServletResponse, filterChain);
                        //验证成功后，刷新redis时间
                        redisService.TimeRedis(tokenHeader);
                    } else {
                        throw new CustomSecurityException("用户信息已过期");
                    }
                } else
                    throw new CustomSecurityException("用户信息无效");
            } else
                throw new CustomSecurityException("无用户信息，请重新登录");
        } catch (AuthenticationException e) {
            loginFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e);
        }
    }

}
